package com.bolt.admin.module.sys.service;

import com.bolt.admin.module.sys.dto.MenuDTO;
import com.bolt.admin.module.sys.dto.converter.MenuConverter;
import com.bolt.admin.module.sys.entity.*;
import com.bolt.admin.module.sys.repository.MenuRepository;
import com.bolt.admin.security.shiro.AuthContextHolder;
import com.bolt.admin.security.shiro.DefaultAuthUserDetails;
import com.bolt.common.collection.IteratorUtil;
import com.bolt.common.utils.StrUtil;
import com.bolt.core.view.components.FormItem;
import com.bolt.core.view.components.ListDataLoad;
import com.bolt.support.base.service.BaseTreeService;
import com.bolt.support.spring.jpa.repository.BasicJpaRepository;
import com.bolt.support.ui.tree.vo.UITreeNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统菜单管理
 *
 * @author michao
 *         Created by Administrator on 2017/8/7.
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class MenuService extends BaseTreeService <MenuEntity, Long> implements ListDataLoad {

    @Autowired
    private MenuRepository menuRepository;

    @Autowired
    private PrivilegeService privilegeService;

    @Autowired
    private UserService userService;


    @Override
    protected BasicJpaRepository <MenuEntity, Long> getRepository() {
        return menuRepository;
    }


    @Transactional(rollbackFor = Exception.class)
    public MenuEntity saveOrUpdate(MenuDTO menuDTO) {
        MenuEntity entity = MenuConverter.toEntity(menuDTO);
        return save(entity);
    }


    /**
     * 根据菜单重构权限资源配置表
     */
    @Transactional(rollbackFor = Exception.class)
    public void impMenu2Privilege(Long menuId) {
        List <MenuEntity> menus = new ArrayList();
        if (menuId == null) {
            List <PrivilegeEntity> privileges = privilegeService.findAllCached();
            privilegeService.delete(privileges);
            menus = menuRepository.findAllChildrenMenu();
        } else {
            List <PrivilegeEntity> privileges = privilegeService.findMenuButtonPrivilege(menuId);
            privilegeService.delete(privileges);
            MenuEntity menu = menuRepository.getOne(menuId);
            menus.add(menu);
        }

        for (MenuEntity menu : menus) {
            if (StrUtil.isBlank(menu.getUrl())) {
                continue;
            }
            String url = menu.getUrl();
            String code = StrUtil.subSuf(url, url.indexOf("admin"));
            PrivilegeEntity privilege = new PrivilegeEntity();
            privilege.setCode(code.replace('/', ':'));
            privilege.setMenuId(menu.getId());
            privilege.setType(PrivilegeEntity.PrivilegeTypeEnum.URL);
            privilege.setOrderRank(0);
            privilege.setTitle(menu.getName());
            privilegeService.save(privilege);

            //默认追加增删除三个按钮
            PrivilegeEntity add = new PrivilegeEntity();
            add.setCode(privilege.getCode() + ",create");
            add.setMenuId(menu.getId());
            add.setType(PrivilegeEntity.PrivilegeTypeEnum.BUTTON);
            add.setOrderRank(1);
            add.setTitle("新增");
            privilegeService.save(add);


            PrivilegeEntity update = new PrivilegeEntity();
            update.setCode(privilege.getCode() + ",edit");
            update.setMenuId(menu.getId());
            update.setType(PrivilegeEntity.PrivilegeTypeEnum.BUTTON);
            update.setOrderRank(2);
            update.setTitle("编辑");
            privilegeService.save(update);


            PrivilegeEntity del = new PrivilegeEntity();
            del.setCode(privilege.getCode() + ",del");
            del.setMenuId(menu.getId());
            del.setType(PrivilegeEntity.PrivilegeTypeEnum.BUTTON);
            del.setOrderRank(3);

            del.setTitle("删除");
            privilegeService.save(del);


        }

    }

    /**
     * 针对父级菜单排序号修改，将对其所有子项排序号进行修改
     *
     * @param self
     */
    private void updateAllChildrenOrderRank(MenuEntity self) {
        Integer orderNum = self.getOrderRank();
        Integer subOrderNum = (orderNum * 10);
        List <MenuEntity> children = findChildren(self.getId());
        if (!IteratorUtil.isEmpty(children)) {
            for (MenuEntity item : children) {
                subOrderNum++;
                item.setOrderRank(subOrderNum);
                updateAllChildrenOrderRank(item);
            }
        }

    }

    /**
     * 删除操作
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(MenuEntity entity) {
        //同步清理自动创建的对应权限数据
        if (entity.getParent() != null && entity.getParent() != null) {
            MenuEntity parent = menuRepository.getOne(entity.getParent().getId());
        }
        super.delete(entity);
    }

    /**
     * 取出所一级菜单
     */
    public List <MenuEntity> findRoots() {
        List <MenuEntity> allMenus = findAllCached();
        return allMenus.stream().filter(one -> one.getParent() == null && one.getEnabled()).collect(Collectors.toList());
    }


    /**
     * 取出所有缓存菜单信息
     *
     * @return
     */
    public List <MenuEntity> findAllCached() {
        return menuRepository.findAllCached();
    }


    private List <UITreeNode> findNavMenu(Long parentId, boolean isSuper, Set <Long> userPrivileges) {
        List <UITreeNode> availableMenus = new ArrayList();
        List <MenuEntity> menus = null;
        if (null == parentId) {
            menus = findRoots();
        } else {
            menus = findChildren(parentId);
        }
        for (MenuEntity menu : menus) {
            boolean matched = true;

            // 如果是超级管理员直接返回所有有效菜单
            if (!isSuper && menu.hasChildren()) {//只有子结点验证
                matched = filterPrivilegeMenu(menu, userPrivileges);
            }

            if (matched) {
                UITreeNode node = new UITreeNode();
                node.setTitle(menu.getName());
                node.setId(String.valueOf(menu.getId()));
                node.setIcon(menu.getIcon());
                node.setParent(menu.hasChildren());
                Map <String, String> attribute = new HashMap();
                attribute.put("name", menu.getName());
                attribute.put("code", String.valueOf(menu.getId()));
                attribute.put("orderRank", String.valueOf(menu.getOrderRank()));
                node.setAttribute(attribute);
                node.setUrl(menu.getUrl());

                if (menu.hasChildren()) {
                    List <UITreeNode> childrens = findNavMenu(menu.getId(), isSuper, userPrivileges);
                    node.setChildren(childrens);
                } else {
                    node.setChildren(new LinkedList());
                }
                availableMenus.add(node);

            }


        }
        return availableMenus;
    }

    /**
     * 用于前端数据展示
     *
     * @param formItem
     * @param map
     * @return
     */
    @Override
    public Map <String, String> load(FormItem formItem, Map  map) {
        Map <String, String> r = new LinkedHashMap <>();
        Iterable <MenuEntity> roots = this.findRoots();
        r.put("", "无上级");
        for (MenuEntity menu : roots) {
            r.put(String.valueOf(menu.getId()), menu.getName());
            buildComboxOption(r, menu);
        }
        return r;
    }

    /**
     * 生成菜单下拉列表数据
     *
     * @param r
     * @param menu
     */
    private void buildComboxOption(Map <String, String> r, MenuEntity menu) {
        List <MenuEntity> childrens = this.findChildren(menu.getId());
        for (MenuEntity children : childrens) {
            StringBuffer formatText = new StringBuffer();
            for (int i = 0; i < children.getLevel(); i++) {
                formatText.append("&#160;&#160;");
            }
            formatText.append("|-");
            formatText.append(children.getName());
            r.put(String.valueOf(children.getId()), formatText.toString());
            buildComboxOption(r, children);
        }
    }


    /**
     * 计算用户有访问权限的菜单列表
     *
     * @param menu
     * @param userPrivileges
     * @return
     */
    private boolean filterPrivilegeMenu(MenuEntity menu, Set <Long> userPrivileges) {
        boolean matched = false;
        for (Long userPrivilege : userPrivileges) {
            if (menu.getId().equals(userPrivilege)) {
                matched = true;
                break;
            }
        }
        return matched;
    }
    @Override
    protected void converterTreeNode(MenuEntity entity, UITreeNode treeNode) {
        super.converterTreeNode(entity, treeNode);
        treeNode.setName(entity.getName());
        Map<String,String> data = new HashMap <>();
        data.put("path",entity.getUrl());
        treeNode.setAttribute(data);
    }

    /**
     * 过虑用于前台显示的菜单列表
     *
     * @return
     */
    public List <UITreeNode> authUserMenu() {
        DefaultAuthUserDetails authUserDetails = (DefaultAuthUserDetails)AuthContextHolder.getAuthUserDetails();
        UserEntity user = userService.findOne(authUserDetails.getAccountId()).get();
        List <UserR2Role> userR2Roles = user.getUserR2Roles();
        Set <Long> userPrivileges = new HashSet();
        for (UserR2Role userR2Role : userR2Roles) {
            RoleEntity role = userR2Role.getRole();
            // 如果是超级管理员直接返回所有有效菜单
            List <RoleR2Privilege> roleR2Privileges = role.getRoleR2Privileges();
            for (RoleR2Privilege roleR2Privilege : roleR2Privileges) {
                if (roleR2Privilege.getPrivilege().getType().equals(PrivilegeEntity.PrivilegeTypeEnum.URL)) {
                    userPrivileges.add(roleR2Privilege.getPrivilege().getMenuId());
                }
            }
        }
        List <UITreeNode> navMenus = findNavMenu(null, authUserDetails.getUserDTO().isAdmin(), userPrivileges);
        removeEmptyParentItem(navMenus);
        return navMenus;
    }


    private void removeEmptyParentItem(List <UITreeNode> navMenus) {
        for (Iterator <UITreeNode> it = navMenus.iterator(); it.hasNext(); ) {
            UITreeNode item = it.next();
            if (!item.hasChildren() && item.isParent()) {
                it.remove();
                continue;
            }
            if (item.hasChildren()) {
                removeEmptyParentItem(item.getChildren());
            }
        }
    }

}
